package splab.ufcg.edu.br.indexer;

import java.io.File;

import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.HttpSolrServer;
import org.apache.solr.common.SolrInputDocument;

import splab.ufcg.edu.br.entities.TraceLink;
import splab.ufcg.edu.br.entities.TraceLinkList;
import splab.ufcg.edu.br.exceptions.IndexException;
import splab.ufcg.edu.br.indexer.util.ConnectionProperties;
import splab.ufcg.edu.br.indexer.util.ExecutionMode;
import splab.ufcg.edu.br.indexer.util.IndexerProperties;
import splab.ufcg.edu.br.interfaces.Indexable;
import splab.ufcg.edu.br.interfaces.Translatable;
import splab.ufcg.edu.br.writer.TraceLinkWriter;

public class ApacheSolrJIndexer implements Indexable {

	private static final String DELETE_ALL_INDEXES = "*:*";

	private static final String ID_FIELD = "id";

	private final String REQUIREMENT_FIELD = "requirement";

	private static final String SEMANTIC_FIELD = "semantic";

	private static final String ARTIFACT_FIELD = "artifact";

	private static final String ARTIFACT_TYPE_FIELD = "artifact_type";

	private static final long COMMIT_LOT_SIZE = 1000;

	private ConnectionProperties connectionProperties;

	private IndexerProperties indexerProperties;

	private Translatable traceLinkWriter;

	private TraceLinkList tracelinkList;

	public ApacheSolrJIndexer() {

	}

	@Override
	public void indexTraceLinks() throws IndexException {

		try {

			if (ExecutionMode.FULL.equals(indexerProperties.getMode())) {
				this.clearIndexdatabase();

				this.importTraceLinks();

			} else {
				throw new IndexException("Not yet implemented");
			}

		} catch (SolrServerException ex) {

			StringBuilder message = new StringBuilder();
			message.append("Could not establish connection with Solr server: ");
			message.append(this.connectionProperties.getConnectionUrl());

			throw new IndexException(message.toString(), ex);

		} catch (Exception ex) {

			StringBuilder message = new StringBuilder();
			message.append("Unexpected error while indexing tracelinks: ");
			message.append(ex.getMessage());

			throw new IndexException(message.toString(), ex);
		}
	}

	private void importTraceLinks() throws Exception {

		File folder = new File(this.indexerProperties.getDirectory());

		if (folder.exists()) {

			File[] fileList = folder.listFiles();

			for (File file : fileList) {
				traceLinkWriter = new TraceLinkWriter();

				this.tracelinkList = traceLinkWriter.read(file);

				if (canIndex()) {
					this.indexImportedTraceLinks();
				}
			}

		} else {

			StringBuilder message = new StringBuilder();
			message.append("Could not find directory to import trace links: ");
			message.append(this.indexerProperties.getDirectory());

			throw new IndexException("");
		}

	}

	private void indexImportedTraceLinks() throws SolrServerException,
			Exception {

		HttpSolrServer server = new HttpSolrServer(
				this.connectionProperties.getConnectionUrl());

		long count = 0;

		for (TraceLink tracelink : this.tracelinkList.getTraceLinks()) {

			Long currentID = SolrJID.getInstance().getCurrentId();

			SolrInputDocument doc = new SolrInputDocument();
			doc.addField(ID_FIELD, currentID != null ? currentID.toString() : "");
			doc.addField(REQUIREMENT_FIELD, tracelink.getRequirement());
			doc.addField(SEMANTIC_FIELD, tracelink.getSemantic());
			doc.addField(ARTIFACT_TYPE_FIELD, tracelink.getArtifactType());
			doc.addField(ARTIFACT_FIELD, tracelink.getArtifact());

			if (count % COMMIT_LOT_SIZE == 0) {
				server.commit();
			}
			server.add(doc);
			count++;
		}

		server.commit();

	}

	@Override
	public void clearIndexdatabase() throws IndexException {

		try {
			HttpSolrServer server = new HttpSolrServer(
					this.connectionProperties.getConnectionUrl());

			server.deleteByQuery(DELETE_ALL_INDEXES);

			server.commit();

		} catch (SolrServerException ex) {
			StringBuilder message = new StringBuilder();
			message.append("Could not establish connection with Solr server: ");
			message.append(this.connectionProperties.getConnectionUrl());

			throw new IndexException(message.toString(), ex);

		} catch (Exception ex) {

			StringBuilder message = new StringBuilder();
			message.append("Unexpected error while purging index database");

			throw new IndexException(message.toString(), ex);
		}
	}

	private boolean canIndex() {
		return tracelinkList != null & tracelinkList.getTraceLinks() != null
				&& tracelinkList.getTraceLinks().size() > 0;
	}

}
